package com.rules.admin.controller;

import com.rules.admin.publish.RedisNotifer;
import com.rules.admin.utils.ResultUtils;
import com.gillion.grule.client.core.DroolsRuleCompiler;
import com.gillion.grule.client.core.variable.PackageVariable;
import com.gillion.grule.client.logger.LoggerAppender;
import com.gillion.grule.client.logger.LoggerAppenderHolder;
import com.gillion.grule.client.sync.DroolsRulePackage;
import com.rules.admin.entity.ParserContext;
import com.rules.admin.entity.RulePackage;
import com.rules.admin.parser.DroolsRuleParser;

import com.rules.admin.service.*;
import com.rules.admin.unit.TestResult;
import com.rules.admin.unit.UnitCase;
import com.rules.admin.unit.UnitCaseExecutor;
import com.google.common.collect.Lists;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;

@RequestMapping({"/rulePublish"})
@Controller
public class RulePublishController {
   @Autowired
   private RulePackageService rulePackageService;
   @Autowired
   private DroolsRuleParser droolsRuleParser;
   @Autowired
   private DroolsRuleParser unitTestDroolsRuleParser;
   @Autowired
   private UnitCaseExecutor unitCaseExecutor;
   @Autowired
   private UnitCaseService unitCaseService;
   @Autowired
   private RedisNotifer redisNotifer;
   @Autowired
   private RuleVariableService ruleVariableService;
   @Autowired
   private DataSourceModelService dataSourceModelService;
   @Autowired
   private RemoteService remoteService;
   @Autowired
   private SpringCloudService springCloudService;
   @Autowired
   private GroovyShellService groovyShellService;
   @Autowired
   private DubboService dubboService;
   @Autowired
   private ValidatorService validatorService;
   private DroolsRuleCompiler droolsRuleCompiler = new DroolsRuleCompiler();

   @RequestMapping(
      value = {"/compile/{id}"},
      method = {RequestMethod.GET}
   )
   @ResponseBody
   public Map<String, Object> compile(@PathVariable("id") Long id) {
      LoggerAppenderHolder.save(new LoggerAppender());
      RulePackage rulePackage = this.rulePackageService.getById(id);

      try {
         LoggerAppenderHolder.log("开始编译", new Object[0]);
         this.droolsRuleParser.parser(rulePackage, new ParserContext());
         LoggerAppenderHolder.log("编译通过", new Object[0]);
      } catch (Exception var4) {
         LoggerAppenderHolder.log("编译异常:{}", new Object[]{ExceptionUtils.getStackTrace(var4)});
         return ResultUtils.getFaildResultData(new String[]{LoggerAppenderHolder.get().getMessage()});
      }

      return ResultUtils.getSuccessResultData(LoggerAppenderHolder.get().getMessage());
   }

   @RequestMapping(
      value = {"/test/{id}"},
      method = {RequestMethod.GET}
   )
   @ResponseBody
   public Map<String, Object> test(@PathVariable("id") Long id, Long[] unitCaseIds) {
      LoggerAppenderHolder.save(new LoggerAppender());
      RulePackage rulePackage = this.rulePackageService.getById(id);
      List<TestResult> testList = Lists.newArrayList();
      ParserContext parserContext = new ParserContext(true);
      if (rulePackage.getPackageStatus() != 0) {
         return rulePackage.getPackageStatus() == 1 ? ResultUtils.getFaildResultData(new String[]{"此规则包已被禁用"}) : ResultUtils.getFaildResultData(new String[]{"此规则包已被终止"});
      } else {
         Map map;
         try {
            LoggerAppenderHolder.log("开始编译测试包", new Object[0]);
            if (!this.test(unitCaseIds, testList, id, rulePackage, parserContext)) {
               LoggerAppenderHolder.log("测试失败", new Object[0]);
               map = ResultUtils.getSuccessResultData(LoggerAppenderHolder.get().getMessage());
               map.put("result", testList);
               map.put("testId", parserContext.getTestId());
               return map;
            }

            LoggerAppenderHolder.log("所有测试用例测试通过", new Object[0]);
         } catch (Exception var8) {
            LoggerAppenderHolder.log("测试异常:{}", new Object[]{ExceptionUtils.getStackTrace(var8)});
            map = ResultUtils.getSuccessResultData(LoggerAppenderHolder.get().getMessage());
            map.put("result", testList);
            map.put("testId", parserContext.getTestId());
            return map;
         }

         map = ResultUtils.getSuccessResultData(LoggerAppenderHolder.get().getMessage());
         map.put("result", testList);
         map.put("testId", parserContext.getTestId());
         return map;
      }
   }

   private boolean test(Long[] unitCaseIds, List<TestResult> list, Long id, RulePackage rulePackage, ParserContext parserContext) throws Exception {
      Boolean success = true;
      Long[] unitCaseIdList = unitCaseIds;
      int unitCaseIdsLength = unitCaseIds.length;

      for(int i = 0; i < unitCaseIdsLength; ++i) {
         Long unitCaseId = unitCaseIdList[i];
         //规则包解析
         DroolsRulePackage unitDroolsRulePackage = this.unitTestDroolsRuleParser.parser(rulePackage, parserContext);
         //规则包变量加载
         PackageVariable packageVariable = this.ruleVariableService.loadCompletelyPackageVaribles(id);
         unitDroolsRulePackage.setVariables(packageVariable);
         unitDroolsRulePackage.setDataSources(this.dataSourceModelService.selectMapByProjectCode(rulePackage.getGroupId()));
         unitDroolsRulePackage.setRemoteConfig(this.remoteService.selectListByProjectCode(rulePackage.getGroupId()));
         unitDroolsRulePackage.setSpringCloudConfig(this.springCloudService.selectListByProjectCode(rulePackage.getGroupId()));
         unitDroolsRulePackage.setDubboConfigs(this.dubboService.selectListByProjectCode(rulePackage.getGroupId()));
         unitDroolsRulePackage.setGroovyShellConfigs(this.groovyShellService.selectListByProjectCode(rulePackage.getGroupId()));
         unitDroolsRulePackage.setValidatorConfig(this.validatorService.findByProjectId(rulePackage.getProjectid()));
         UnitCase unitCase = this.unitCaseService.converterToUnitCase(unitCaseId);

         try {
            unitDroolsRulePackage.compile(this.droolsRuleCompiler);
         } catch (Exception exception) {
            LoggerAppenderHolder.log("测试用例：{}测试失败,失败原因：{}", new Object[]{unitCase.getUnitCaseName(), ExceptionUtils.getStackTrace(exception)});
            TestResult testResult = new TestResult();
            testResult.setMes(false, unitCase.getUnitCaseName(), "测试失败，请检查规则配置！");
            list.add(testResult);
            return false;
         }

         TestResult testResult = new TestResult();

         try {
            this.unitCaseExecutor.execute(unitDroolsRulePackage, unitCase);
            testResult.setMes(true, unitCase.getUnitCaseName(), "成功！");
            list.add(testResult);
         } catch (Exception var16) {
            LoggerAppenderHolder.log("测试用例：{}测试失败,失败原因：{}", new Object[]{unitCase.getUnitCaseName(), ExceptionUtils.getStackTrace(var16)});
            success = false;
            testResult.setMes(false, unitCase.getUnitCaseName(), var16.getMessage());
            list.add(testResult);
         }
      }

      return success;
   }

   @RequestMapping(
      value = {"/publish/{id}"},
      method = {RequestMethod.GET}
   )
   @ResponseBody
   public Map<String, Object> publish(@PathVariable("id") Long id, String version, Long[] unitCaseIds) {
      List<TestResult> testList = Lists.newArrayList();
      Map map = new HashedMap();
      map.put("packageId", String.valueOf(id));
      if (version == null) {
         Map versionErr = new HashedMap();
         map.put("mes", "版本号为空，请先填写版本号");
         versionErr.put("data", map);
         versionErr.put("success", false);
         return versionErr;
      } else if (version.length() > 5) {
         return ResultUtils.getFaildResultData(new String[]{"版本号过长，请重新命名！"});
      } else {
         LoggerAppenderHolder.save(new LoggerAppender());
         RulePackage rulePackage = this.rulePackageService.getById(id);
         List<RulePackage> rulePackages = this.rulePackageService.getRulePackages(rulePackage.getGroupId(), rulePackage.getArtifactId());
         if (rulePackages.stream().filter((rule) -> {
            return rule.getVersion().equals(version);
         }).count() > 0L) {
            Map versionErr = new HashedMap();
            map.put("mes", "版本：" + version + " 已存在，请重新命名版本号！");
            versionErr.put("data", map);
            versionErr.put("success", false);
            return versionErr;
         } else {
            try {
               LoggerAppenderHolder.log("开始编译测试包", new Object[0]);
               DroolsRulePackage unitDroolsRulePackage = this.unitTestDroolsRuleParser.parser(rulePackage, new ParserContext(false));
               Long[] var22 = unitCaseIds;
               int var10 = unitCaseIds.length;

               for(int var11 = 0; var11 < var10; ++var11) {
                  Long unitCaseId = var22[var11];
                  TestResult testResult = new TestResult();
                  UnitCase unitCase = this.unitCaseService.converterToUnitCase(unitCaseId);
                  PackageVariable packageVariable = this.ruleVariableService.loadCompletelyPackageVaribles(id);
                  unitDroolsRulePackage.setVariables(packageVariable);
                  unitDroolsRulePackage.setDataSources(this.dataSourceModelService.selectMapByProjectCode(rulePackage.getGroupId()));
                  unitDroolsRulePackage.setRemoteConfig(this.remoteService.selectListByProjectCode(rulePackage.getGroupId()));
                  unitDroolsRulePackage.setSpringCloudConfig(this.springCloudService.selectListByProjectCode(rulePackage.getGroupId()));
                  unitDroolsRulePackage.setDubboConfigs(this.dubboService.selectListByProjectCode(rulePackage.getGroupId()));
                  unitDroolsRulePackage.setValidatorConfig(this.validatorService.findByProjectId(rulePackage.getProjectid()));
                  unitDroolsRulePackage.setGroovyShellConfigs(this.groovyShellService.selectListByProjectCode(rulePackage.getGroupId()));
                  unitDroolsRulePackage.compile(this.droolsRuleCompiler);

                  try {
                     this.unitCaseExecutor.execute(unitDroolsRulePackage, unitCase);
                     testResult.setMes(true, unitCase.getUnitCaseName(), "成功！");
                     testList.add(testResult);
                  } catch (Exception var18) {
                     LoggerAppenderHolder.log("测试用例：{}测试失败,失败原因：{}", new Object[]{unitCase.getUnitCaseName(), ExceptionUtils.getStackTrace(var18)});
                     testResult.setMes(false, unitCase.getUnitCaseName(), var18.toString());
                     map.put("mes", LoggerAppenderHolder.get().getMessage());
                     testList.add(testResult);
                     Map errReturn = new HashedMap();
                     errReturn.put("success", false);
                     errReturn.put("data", map);
                     errReturn.put("result", testList);
                     return errReturn;
                  }
               }

               LoggerAppenderHolder.log("所有测试用例测试通过", new Object[0]);
               RulePackage newRulePackage = this.rulePackageService.updateRulePackageByPublish(id, version);
               LoggerAppenderHolder.log("开始发布", new Object[0]);
               this.redisNotifer.notify(rulePackage);
               LoggerAppenderHolder.log("发布通过", new Object[0]);
               map.put("packageId", String.valueOf(newRulePackage.getId()));
               map.put("mes", LoggerAppenderHolder.get().getMessage());
               map.put("result", testList);
               return ResultUtils.getSuccessResultData(map);
            } catch (Exception var19) {
               LoggerAppenderHolder.log("发布异常:{}", new Object[]{ExceptionUtils.getStackTrace(var19)});
               map.put("mes", LoggerAppenderHolder.get().getMessage());
               Map errReturn = new HashedMap();
               errReturn.put("success", false);
               errReturn.put("data", map);
               map.put("result", testList);
               return errReturn;
            }
         }
      }
   }
}
